/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.gac.gacmod.core;

import org.gac.gacmod.utils.PluginServices;
import java.beans.IntrospectionException;
import java.beans.PropertyVetoException;
import java.io.File;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.logging.Logger;
import javax.swing.JComponent;
import org.gac.api.genetics.Chromosome;
import org.gac.api.genetics.FitnessFunction;
import org.gac.api.genetics.Population;
import org.gac.gacmod.genetics.ExecutionInput;
import org.gac.gacmod.model.CompositeStep;
import org.gac.gacmod.model.ExampleStep;
import org.gac.gacmod.model.IStepStateListener;
import org.gac.gacmod.model.SequenceStep;
import org.gac.gacmod.model.SplitStep;
import org.gac.gacmod.model.Step;
import org.gac.gacmod.propertysheet.StepNode;
import org.gac.gacmod.visual.BoxScene;
import org.gac.gacmod.visual.SceneFactory;
import org.gac.gacmod.visual.StepWidgetBase;
import org.openide.explorer.ExplorerManager;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
//import org.openide.util.Utilities;

/**
 * Top component which displays something.
 */
final class flowchartDiagramTopComponent extends TopComponent implements ExplorerManager.Provider
{

    private static flowchartDiagramTopComponent instance;
    private BoxScene scene = null;
    private JComponent mainView = null;
    private Step modelRootStep = GenerateHugeTree();
    /** path to the icon used by the component and its open action */
    //static final String ICON_PATH = "system-run.png";
    private static final String PREFERRED_ID = "flowchartDiagramTopComponent";

    public flowchartDiagramTopComponent()
    {

        //System.
        initComponents();
        setName(NbBundle.getMessage(flowchartDiagramTopComponent.class,
                "CTL_flowchartDiagramTopComponent"));
        setToolTipText(NbBundle.getMessage(flowchartDiagramTopComponent.class,
                "HINT_flowchartDiagramTopComponent"));
//        setIcon(Utilities.loadImage(ICON_PATH, true));

        this.scene = new BoxScene();
        this.mainView = this.scene.createView();

        StepWidgetBase swb = new SceneFactory().CreateWidgets(this.scene,
                modelRootStep);
        this.scene.getMainLayer().addChild(swb);

        this.jScrollPane1.setViewportView(this.mainView);

        modelRootStep.setStepChangeListener(
                new IStepStateListener()
                {

                    public void StepStateChanged(Step step)
                    {
                        flowchartDiagramTopComponent.this.regenerateScene(scene);
                    }
                });

        associateLookup(Lookups.fixed(new Object[]
                {
                    StepPaletteHelper.createPalette()
                }));

        scene.setSelectionListener(new BoxScene.SelectionListener()
        {

            public void selectionChanged(StepWidgetBase newSelection)
            {
                if( newSelection != null )
                {
                    Node nd = null;
                    try
                    {
                        nd = new StepNode(newSelection.getModelStep());
                    } catch (IntrospectionException ex)
                    {
                        Exceptions.printStackTrace(ex);
                    }
                    mgr.setRootContext( nd );
                    try
                    {
                        mgr.setSelectedNodes(new Node[]{nd});
                        setActivatedNodes(new Node[]{nd});
                    } catch (PropertyVetoException ex)
                    {
                        Exceptions.printStackTrace(ex);
                    }
                }
                else
                    mgr.setRootContext(null);

            }
            
        }
        );
    }

    private void regenerateScene(BoxScene scene)
    {
        scene.clear();
        StepWidgetBase swb = new SceneFactory().CreateWidgets(this.scene,
                modelRootStep);
        this.scene.getMainLayer().addChild(swb);
        this.scene.validate();
    }

    public static CompositeStep GenerateSeq()
    {
        SequenceStep result = new SequenceStep("Sequence1");
        result.AddStep(new ExampleStep("Crossing-over"));
        result.AddStep(new ExampleStep("Mutation"));
        result.AddStep(new ExampleStep("Crossing-over"));
        result.AddStep(new ExampleStep("Inversion"));
        result.AddStep(new ExampleStep("Mutation"));
        result.AddStep(new ExampleStep("Crossing-over"));
        return result;
    }

    public static CompositeStep GenerateSplit()
    {
        SplitStep result = new SplitStep("Split1");
        result.AddStep(new ExampleStep("Crossing-over"));
        result.AddStep(new ExampleStep("Mutation"));
        result.AddStep(new ExampleStep("Crossing-over"));
        result.AddStep(new ExampleStep("Inversion"));
        return result;
    }

    public static CompositeStep GenerateBigTree()
    {
        SequenceStep result = new SequenceStep("Sequence2");

        result.AddStep(GenerateSplit());
        result.AddStep(GenerateSplit());

        result.AddStep(new ExampleStep("Crossing-over"));

        result.AddStep(new ExampleStep("Crossing-over"));
        result.AddStep(GenerateSplit());
        result.AddStep(GenerateSplit());
        return result;
    }

    public static CompositeStep GenerateHugeTree()
    {
        SplitStep result = new SplitStep("Split2");
        result.AddStep(GenerateBigTree());
        result.AddStep(GenerateSeq());

        result.AddStep(GenerateBigTree());
        return result;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jToolBar1 = new javax.swing.JToolBar();
        jButton1 = new javax.swing.JButton();
        jSeparator1 = new javax.swing.JToolBar.Separator();
        jButton2 = new javax.swing.JButton();
        jButton3 = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();

        setLayout(new java.awt.BorderLayout());

        jToolBar1.setFloatable(false);
        jToolBar1.setRollover(true);

        org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(flowchartDiagramTopComponent.class, "flowchartDiagramTopComponent.jButton1.text")); // NOI18N
        jButton1.setFocusable(false);
        jButton1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton1.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        jToolBar1.add(jButton1);
        jToolBar1.add(jSeparator1);

        org.openide.awt.Mnemonics.setLocalizedText(jButton2, org.openide.util.NbBundle.getMessage(flowchartDiagramTopComponent.class, "flowchartDiagramTopComponent.jButton2.text")); // NOI18N
        jButton2.setFocusable(false);
        jButton2.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton2.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });
        jToolBar1.add(jButton2);

        org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(flowchartDiagramTopComponent.class, "flowchartDiagramTopComponent.jButton3.text")); // NOI18N
        jButton3.setFocusable(false);
        jButton3.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton3.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jToolBar1.add(jButton3);

        add(jToolBar1, java.awt.BorderLayout.NORTH);
        add(jScrollPane1, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jButton2ActionPerformed
    {//GEN-HEADEREND:event_jButton2ActionPerformed
       //Run algorithm
        this.modelRootStep.Run( new ExecutionInput( new FitnessFunction() {

            public double evaluate(Chromosome c)
            {
                return 0;
            }
        }, new Population()) );
    }//GEN-LAST:event_jButton2ActionPerformed

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jButton1ActionPerformed
    {//GEN-HEADEREND:event_jButton1ActionPerformed
        //Class c = FitnessFunction.class;
        //System.out.println(c.getCanonicalName());

        System.out.println("===" + FitnessFunction.class.getClassLoader().getClass().getCanonicalName());
        System.out.println("===" + ClassLoader.getSystemClassLoader().getClass().getCanonicalName());
        
        try
        {
            Thread.sleep(500);
        } catch (InterruptedException ex)
        {
            Exceptions.printStackTrace(ex);
        }
        for( FitnessFunction f: PluginServices.getInstance().getPlugins())
        {
            System.out.println( f.evaluate(new Chromosome()));
        }



        //> cleanup
//        try
//        {
//            try
//            {
                //Lookup.getDefault().lookup(FitnessFunction.class);
//                ServiceLoader<FitnessFunction> f = ServiceLoader.load(FitnessFunction.class);
//
////                for( FitnessFunction f2: Lookup.getDefault().lookupAll(FitnessFunction.class))
////                {
////                    JOptionPane.showMessageDialog(null, f2.getClass().getCanonicalName());
////                }
//                //FitnessFunction f1 = (FitnessFunction) Class.forName("org.gac.ext.ex1.MyFitnessFunction", true, FitnessFunction.class.getClassLoader()).newInstance();
//                //f1.evaluate(new Chromosome());
//                for( FitnessFunction fit: f)
//                {
//                    JOptionPane.showMessageDialog(null, fit.getClass().getCanonicalName());
//                }
                
//            } catch (InstantiationException ex)
//            {
//                Exceptions.printStackTrace(ex);
//            } catch (IllegalAccessException ex)
//            {
//                Exceptions.printStackTrace(ex);
//            }
            //for( FitnessFunction fit: f)
            //{
            //    JOptionPane.showMessageDialog(null, fit.getClass().getCanonicalName());
            //}
            //Lookup.getDefault().lookup(FitnessFunction.class);
//        } catch (ClassNotFoundException ex)
//        {
//            Exceptions.printStackTrace(ex);
//        }
        //for( FitnessFunction fit: f)
        //{
        //    JOptionPane.showMessageDialog(null, fit.getClass().getCanonicalName());
        //}
                
                //Lookup.getDefault().lookup(FitnessFunction.class);
        
    }//GEN-LAST:event_jButton1ActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JToolBar.Separator jSeparator1;
    private javax.swing.JToolBar jToolBar1;
    // End of variables declaration//GEN-END:variables

    /**
     * Gets default instance. Do not use directly: reserved for *.settings files only,
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
     * To obtain the singleton instance, use {@link #findInstance}.
     */
    public static synchronized flowchartDiagramTopComponent getDefault()
    {
        if (instance == null)
        {
            instance = new flowchartDiagramTopComponent();
        }
        return instance;
    }

    /**
     * Obtain the flowchartDiagramTopComponent instance. Never call {@link #getDefault} directly!
     */
    public static synchronized flowchartDiagramTopComponent findInstance()
    {
        TopComponent win = WindowManager.getDefault().findTopComponent(
                PREFERRED_ID);
        if (win == null)
        {
            Logger.getLogger(flowchartDiagramTopComponent.class.getName()).
                    warning(
                    "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
            return getDefault();
        }
        if (win instanceof flowchartDiagramTopComponent)
        {
            return (flowchartDiagramTopComponent) win;
        }
        Logger.getLogger(flowchartDiagramTopComponent.class.getName()).warning(
                "There seem to be multiple components with the '" + PREFERRED_ID +
                "' ID. That is a potential source of errors and unexpected behavior.");
        return getDefault();
    }

    @Override
    public int getPersistenceType()
    {
        return TopComponent.PERSISTENCE_NEVER;
    }

    @Override
    public void componentOpened()
    {
    }

    @Override
    public void componentClosed()
    {
        // TODO add custom code on component closing
    }

    /** replaces this in object stream */
    @Override
    public Object writeReplace()
    {
        return new ResolvableHelper();
    }

    @Override
    protected String preferredID()
    {
        return PREFERRED_ID;
    }

    @Override
    protected void componentActivated()
    {
        SatelliteViewTopComponent satelliteComponent = SatelliteViewTopComponent.
                findInstance();
        //if( satelliteComponent != null )
        satelliteComponent.setSatelliteView(this.scene.createSatelliteView());
    }

    @Override
    protected void componentHidden()
    {
        SatelliteViewTopComponent satelliteComponent = SatelliteViewTopComponent.
                findInstance();
        //if( satelliteComponent != null )
        satelliteComponent.setSatelliteView(null);
    }

    private final ExplorerManager mgr = new ExplorerManager();

    public ExplorerManager getExplorerManager()
    {
        return mgr;
    }

    final static class ResolvableHelper implements Serializable
    {

        private static final long serialVersionUID = 1L;

        public Object readResolve()
        {
            return flowchartDiagramTopComponent.getDefault();
        }
    }
}
